package com.jackykeke.opengldemo.renderer;

import android.opengl.GLES30;
import android.opengl.GLSurfaceView;

import com.jackykeke.opengldemo.R;
import com.jackykeke.opengldemo.utils.ResReadUtil;
import com.jackykeke.opengldemo.utils.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

//顶点数组对象(VAO)
//加载顶点属性的两种不同方式：使用客户顶点数组和使用顶点缓冲区对象。
//
//顶点缓冲区对象优于客户顶点数组，因为它们能够减少CPU和GPU之间复制的数据量，从而获得更好的性能。在OpenGL ES 3.0中引人了一个新特性，使顶点数组的使用更加高效：顶点数组对象(VAO)。
//
//使用顶点缓冲区对象设置绘图操作可能需要多次调用glBindBuffer、glVertexAttribPointer和 glEnableVertexAttribArray。为了更快地在顶点数组配置之间切换，OpenGL ES 3.0推出了顶点数组对象。VAO提供包含在 顶点数组/顶点缓冲区对象配置之间切换所需要的所有状态的单一对象。
//
//OpenGLES 3.0中总是有一个活动的顶点数组对象。之前的一些实例 默认都在顶点数组对象上操作(默认VAO的ID为0)。要创建新的顶点数组对象，可以使用glGenVertexArrays方法。

public class VertexArrayRenderer implements GLSurfaceView.Renderer {

    //    顶点Buffer
    private FloatBuffer vertexBuffer;

    private float[] vertexPoints = new float[]{
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
    };
    private int mProgram;

    private static final int VERTEX_POS_INDEX = 0;

    private static final int VERTEX_POS_SIZE = 3;

    private static final int VERTEX_STRIDE = VERTEX_POS_SIZE * 4;

    /**
     * 缓冲数组
     */
    private int[] vaoIds = new int[1];
    private int[] vboIds = new int[1];

    public VertexArrayRenderer() {
        //分配内存空间，每个浮点型占4字节空间
        vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        //传入指定的坐标数据
        vertexBuffer.put(vertexPoints);
        vertexBuffer.position(0);
    }


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //设置背景颜色
        GLES30.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);

        //编译
        final  int vertexShaderId = ShaderUtil.compileVertexShader(ResReadUtil.readResource(R.raw.vertex_array_shader));
        final  int fragmentShaderId = ShaderUtil.compileFragmentShader(ResReadUtil.readResource(R.raw.fragment_array_shader));
        //鏈接程序片段
        mProgram = ShaderUtil.linkProgram(vertexShaderId, fragmentShaderId);
        //使用程序片段
        GLES30.glUseProgram(mProgram);

//        生成一个缓冲ID
        GLES30.glGenVertexArrays(1, vaoIds, 0);
//        绑定VAO
        GLES30.glBindVertexArray(vaoIds[0]);

//        1、生成一个缓冲ID
        GLES30.glGenBuffers(1, vboIds, 0);
        //2. 向顶点坐标数据缓冲送入数据把顶点数组复制到缓冲中
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboIds[0]);
        GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertexPoints.length * 4, vertexBuffer, GLES30.GL_STATIC_DRAW);

//        3将顶点位置数据送入渲染管线
        GLES30.glVertexAttribPointer(VERTEX_POS_INDEX, VERTEX_POS_SIZE, GLES30.GL_FLOAT, false, VERTEX_STRIDE, 0);

        //启用顶点位置属性
        GLES30.glEnableVertexAttribArray(VERTEX_POS_INDEX);

        //4、解绑VAO
        GLES30.glBindVertexArray(0);

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);

        //使用程序片段
        GLES30.glUseProgram(mProgram);

        //绑定VAO
        GLES30.glBindVertexArray(vaoIds[0]);

        //绘制三角形
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3);

        //7. 解绑VAO
        GLES30.glBindVertexArray(0);

    }
}
